'''
Created on 23/09/2012

@author: Charles Murray
'''

from Parser import *

class StructuralModel(object):
    '''
    Structural Model needs to take into account that there may 
    be times where we can't have the full stream.
    Most times though although we will not be able to get the full
    stream we should be able to get a full record.
    '''


    def __init__(self, filename):
        '''
        Constructor
        '''
        self.parser = Parser(filename)
        self.model = self.parser.parse(self.parser.getRoot())
        self.model = self.parser.linkTags(self.model)
        self.mappings = {}
        self.endings = []
    
    def dataParser(self, stream):
        self.stream = stream
        self.stream = self.stream.split(self.model.getStart(), 1)[1]
        self.clearTree(self.model)
        """
        while (self.stream != self.getRoot().getEnd()):
            self.findData(self.getRoot(), self.stream)
        """
        return self.model
    
    def travrseTree(self, node):
        for item in node.Subtree():
            if item.getSubtree() != None:
                self.traverseTree(item)
    
    def clearTree(self, node):
        for item in node.getSubtree():
            if item.getInfo() == "Container":
                item.setData("")
                if item.getSubtree() != None:
                    self.clearTree(item)
    """
    For root we have something special but everything else
    will go through here. In this if we have two items that 
    have the same index then we use the first found.
    Goes through all of the items in this scope and tries to 
    find a match.
    """
    def findData(self, node, stream):
        currentIndex = len(stream)
        currentItem = None
        if node.getSubtree() != None:
            for item in node.getSubtree():
                #item.setData("")
                try:
                    if stream.index(item.getStart()) < currentIndex:
                        currentIndex = stream.index(item.getStart())
                        currentItem = item
                except ValueError:
                    pass
        if currentItem != None:
            if currentItem.getInfo() == "Option":
                currentItem = currentItem.getLink()
            return self.parseString(node, currentItem, stream)
        return ["", ""]

    def parseString(self, parent, currentItem, stream):  
        #print "Start: " + currentItem.getStart()
        #print "stream: " + stream
        parentStart, data = stream.split(currentItem.getStart(), 1)
        data, parentEnd = data.split(currentItem.getEnd(), 1)
        """
        print "data " + data
        print "stream " + stream
        print "parentStart " + parentStart
        print "parentEnd " + parentEnd
        """
        start , end = self.findData(currentItem, data)
        """
        print start
        print end
        """
        
        if start != "":
            data = start
        elif end != "":
            #print "end: " + end
            #data, stream = end.split(currentItem.getEnd(), 1)
            data = end
            #print "data: " + data
            #print "stream: " + stream
        
        #data = self.checkOptions(parent, currentItem, data)[0]
        currentItem.setData(data)
        self.stream = parentEnd
        return [parentStart, parentEnd]  
    
    """
    Need to find a way to search through the string in
    such a way as so we can go to the next match not just the 
    first match.
    We can use the find method for that.
    """
    def checkOptions(self, node, currentItem, stream):
        self.endings = []
        self.getEndings(node, currentItem)
        print "Start Stream: {0}".format(stream)
        option = False
        start = 0
        while not option:
            index = stream.find(currentItem.getEnd(), start)
            if index == -1:
                break
            option, start = self.checkEndings(stream, currentItem, index, start)
            if option:
                """
                Need to change this to deal with the fact that the next 
                separator in the sequence may not be what we want to 
                split at.
                """
                data = stream[0:index]
                returnStream = stream[index+len(currentItem.getEnd()):len(stream)]
                return [data, returnStream]
        
    def checkEndings(self, stream, currentItem, index, start):
        print "index: {0}".format(index)
        for end in self.endings:
            print "End: {0}".format(end)
            endIndex = stream.find(end, start)
            print "endIndex: {0}".format(endIndex)
            if index >= endIndex and index <= endIndex+int(len(end)) :
                print "End: ".format(end)
                print "Option 1"
                return [False, endIndex+int(len(end))]
            elif index+int(len(currentItem.getEnd())) >= endIndex and index+int(len(currentItem.getEnd())) <= endIndex+int(len(end)):
                print "Option 2"
                return [False, endIndex+int(len(end))]
        return [True, 0]
    
    def getEndings(self, node, currentItem):
        for item in node.getSubtree():
            print "Item: {0}".format(item.getId())
            print "currentItem: {0}".format(currentItem.getId())
            if item.getInfo() != "Option" and item.getId() != currentItem.getId():
                print "Succeeded"
                if item.getEnd() != "":
                    self.endings.append(item.getEnd())
                if item.getStart() != "":
                    self.endings.append(item.getStart())
            if item.getSubtree() != None:
                self.getEndings(item, currentItem)
        
    def getParser(self):
        return self.parser

    def getStream(self):
        return self.stream
    
    def getRoot(self):
        return self.model
    
    def createDict(self, node):
        for item in node.getSubtree():
            if item.getInfo() != "Option":
                self.mappings[item.getMapping()] = item.getData()
                if item.getSubtree() != None:
                    self.createDict(item)

    def getDict(self):
        return self.mappings